﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CPPEI.Net
{
    /// <summary>
    /// |--------------header(8)----------------|  |-data buffer-| |-end(1)-|
    /// beginflag type scenario command datalength       data        endflag
    /// </summary>
    public class Package
    {
        public const int HeaderLength = 8;
        public const int EndLength = 1;

        public const byte SysPackage = 0x01;
        public const byte CustomerPackage = 0x02;

        public const byte BeginFlag = 0xFF;
        public const byte EndFlag = 0xFF;

        /// <summary>
        /// 1byte
        /// 数据包的类型
        /// </summary>
        public byte PackageType { get; private set; }

        /// <summary>
        /// 场景码
        /// 1byte
        /// </summary>
        public byte Scenario { get; private set; }

        /// <summary>
        /// 操作码
        /// 1byte
        /// </summary>
        public byte Command{get; private set;}

        private byte[] _data;

        public byte[] Data
        {
            get
            {
                return _data;
            }
        }

        public bool IsFullPackage { get; private set; }

        /// <summary>
        /// 是否是有效的，true：有效，false：无效
        /// </summary>
        public bool IsValid { get; private set; }

        [Obsolete()]
        public Package(byte command, MemoryStream memoryStream)
            : this(0x02, command, memoryStream)
        {
        }

        [Obsolete()]
        internal Package(byte packageType, byte command, MemoryStream memoryStream)
        {
        }

        /// <summary>
        /// 构建一个数据包
        /// </summary>
        /// <param name="scenario"></param>
        /// <param name="command"></param>
        /// <param name="dataBuffer"></param>
        public Package(byte scenario, byte command, byte[] dataBuffer)
            : this(CustomerPackage, scenario, command, dataBuffer)
        {
        }

        /// <summary>
        /// 构建一个包
        /// </summary>
        /// <param name="packageType">包的类型</param>
        /// <param name="scenario"></param>
        /// <param name="command">操作指令</param>
        /// <param name="dataBuffer"></param>
        public Package(byte packageType, byte scenario, byte command, byte[] dataBuffer)
        {
            this.PackageType = packageType;
            this.Scenario = scenario;
            this.Command = command;
            _data = new byte[dataBuffer.Length];
            System.Buffer.BlockCopy(dataBuffer, 0, _data, 0, dataBuffer.Length);

            IsFullPackage = true;
            this.IsValid = true;
        }

        public Package(byte scenario, byte command, byte[] dataBuffer, int length)
            : this(CustomerPackage, scenario, command, dataBuffer, length)
        {
        }

        public Package(byte packageType, byte scenario,  byte command, byte[] dataBuffer, int length)
        {
            this.PackageType = packageType;
            this.Scenario = scenario;
            this.Command = command;
            _data = new byte[length];
            System.Buffer.BlockCopy(dataBuffer, 0, _data, 0, length);

            IsFullPackage = true;
            this.IsValid = true;
        }

        /// <summary>
        /// 从buffer里获取一个netbuffer数据
        /// </summary>
        /// <param name="buffer"></param>
        public Package(byte[] buffer)
        {
            int offset = 0;
            byte beginFlag = BufferUtil.ByteFromBuffer(buffer, ref offset);
            byte packageType = BufferUtil.ByteFromBuffer(buffer, ref offset);
            byte scenario = BufferUtil.ByteFromBuffer(buffer, ref offset);
            byte command = BufferUtil.ByteFromBuffer(buffer, ref offset);
            int dataLength = BufferUtil.IntFromBuffer(buffer, ref offset);
            offset += dataLength;
            byte endFlag = BufferUtil.ByteFromBuffer(buffer, ref offset);

            if (beginFlag == BeginFlag
                && endFlag == EndFlag)
            {
                this.PackageType = packageType;
                this.Scenario = scenario;
                this.Command = command;
                this._data = new byte[dataLength];
                System.Buffer.BlockCopy(buffer, HeaderLength, _data, 0, dataLength);

                this.IsValid = true;
                this.IsFullPackage = true;
            }
            else
            {
                throw new Exception("数据内容不是一个数据包的格式");
            }
        }

        ///// <summary>
        ///// 计算数据的总长度
        ///// </summary>
        ///// <param name="dataLength"></param>
        ///// <returns></returns>
        //public static ushort CalcBufferLength(ushort dataLength)
        //{
        //    return (ushort)(dataLength + HeaderLength);
        //}

        ///// <summary>
        ///// 构建一个系统内部的数据包
        ///// </summary>
        ///// <param name="command"></param>
        ///// <param name="dataBuffer"></param>
        ///// <returns></returns>
        //internal static Package BuildSysPackage(byte command, byte[] dataBuffer)
        //{
        //    Package package = new Package(0x01, command, dataBuffer);
        //    return package;
        //}

        /// <summary>
        /// 获取包的完整数据
        /// </summary>
        /// <returns></returns>
        public byte[] GetFullBuffer()
        {
            byte[] fullBuffer = new byte[_data.Length + HeaderLength + EndLength];
            int offset = 0;
            BufferUtil.ByteToBuffer(BeginFlag, fullBuffer, ref offset);
            BufferUtil.ByteToBuffer(PackageType, fullBuffer, ref offset);
            BufferUtil.ByteToBuffer(Scenario, fullBuffer, ref offset);
            BufferUtil.ByteToBuffer(Command, fullBuffer, ref offset);
            BufferUtil.IntToBuffer(_data.Length, fullBuffer, ref offset);
            System.Buffer.BlockCopy(_data, 0, fullBuffer, offset, _data.Length);
            offset += _data.Length;
            BufferUtil.ByteToBuffer(EndFlag, fullBuffer, ref offset);

            return fullBuffer;
        }
    }
}
